package com.gao.ranklist.service.impl;


import com.gao.ranklist.constant.Constants;
import com.gao.ranklist.service.HotSearchRanklistService;
import com.gao.ranklist.util.RedisUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ZSetOperations.TypedTuple;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.TimeUnit;

@Service
public class HotSearchRanklistServiceImpl implements HotSearchRanklistService {

    @Autowired
    private RedisUtil redisUtil;

    Logger logger = LoggerFactory.getLogger(HotSearchRanklistServiceImpl.class);

    /**
     * 初始化30天数据
     */
    public void init30DayData() {
        long hour = System.currentTimeMillis() / (1000 * 60 * 60);
        for (int i = 1; i < 24*30; i++) {
            // 倒推过去30天数据
            String key = Constants.HOT_SEARCH_HOUR_KEY + (hour-i);
            initMember(key);
        }
    }

    /**
     * 获取模拟热度数据
     * @param key
     */
    public void initMember(String key) {
        // 获取爬取的模拟热搜数据
        Set<TypedTuple<Object>> tuples = redisUtil.zRangeWithScores(Constants.HOT_SEARCH, 0, redisUtil.zSize(Constants.HOT_SEARCH));
        for (TypedTuple<Object> t: tuples) {
            redisUtil.zAdd(key, t.getValue(), t.getScore());
        }
    }


    /**
     * 刷新小时数据
     */
    public void autoRefreshData() {
        // 刷新当天的数据
        refreshDay();
        // 刷新最近七天的数据
        refreshWeek();
        // 刷新30天的数据
        refreshMonth();
    }

    /**
     * 刷新小时数据
     */
    public void refreshHour() {
        logger.info("刷新每小时数据 Start:");
        long hour = System.currentTimeMillis() / (1000 * 60 * 60);
        initMember(Constants.HOT_SEARCH_HOUR_KEY + hour);
        logger.info("刷新每小时数据 End:");
    }

    /**
     * 刷新当天的数据
     */
    public void refreshDay() {
        logger.info("刷新当天数据 Start:");
        long hour = System.currentTimeMillis() / (1000 * 60 * 60);
        List<String> otherKeys = new ArrayList<>();
        // 计算最近24小时的key
        for (int i = 1; i < 23; i++) {
            String key = Constants.HOT_SEARCH_HOUR_KEY + (hour - i);
            otherKeys.add(key);
        }

        // 把当前时间 key 推后23小时，共24小时，求并集存入 HOT_SEARCH_DAY_KEY 中
        redisUtil.zUnionAndStore(Constants.HOT_SEARCH_HOUR_KEY + hour, otherKeys, Constants.HOT_SEARCH_DAY_KEY);
        // 设置当天的key，40 天过期
        for (int i = 0; i < 24; i++) {
            String key = Constants.HOT_SEARCH_HOUR_KEY + (hour - i);
            redisUtil.expire(key, 40, TimeUnit.DAYS);
        }
        logger.info("刷新当天数据 End:");
    }

    /**
     * 刷新一周的数据
     */
    public void refreshWeek() {
        logger.info("刷新一周数据 Start:");
        long hour = System.currentTimeMillis() / (1000 * 60 * 60);
        List<String> otherKeys = new ArrayList<>();
        // 计算最近24小时的key
        for (int i = 1; i < 24*7 - 1; i++) {
            String key = Constants.HOT_SEARCH_HOUR_KEY + (hour - i);
            otherKeys.add(key);
        }

        // 把当前时间 key 推后24*7-1小时，共24*7小时，求并集存入 HOT_SEARCH_WEEK_KEY 中
        redisUtil.zUnionAndStore(Constants.HOT_SEARCH_HOUR_KEY + hour, otherKeys, Constants.HOT_SEARCH_WEEK_KEY);
        logger.info("刷新一周数据 End:");
    }

    /**
     * 刷新一个月的数据
     */
    public void refreshMonth() {
        logger.info("刷新一个月数据 Start:");
        long hour = System.currentTimeMillis() / (1000 * 60 * 60);
        List<String> otherKeys = new ArrayList<>();
        // 计算最近24小时的key
        for (int i = 1; i < 24*30 - 1; i++) {
            String key = Constants.HOT_SEARCH_HOUR_KEY + (hour - i);
            otherKeys.add(key);
        }

        // 把当前时间 key 推后24*30-1小时，共24*30小时，求并集存入 HOT_SEARCH_MONTH_KEY 中
        redisUtil.zUnionAndStore(Constants.HOT_SEARCH_HOUR_KEY + hour, otherKeys, Constants.HOT_SEARCH_MONTH_KEY);
        logger.info("刷新一个月数据 End:");
    }

    @Override
    public Set getHotSearchRankList(String key, int start, int end) {
        Set<TypedTuple<Object>> typedTuples = redisUtil.zReverseRangeWithScores(key, start, end);
        return typedTuples;
    }

    /**
     * 添加热搜数据的热搜指数
     * @param key
     * @param value
     */
    @Override
    public void addHotSearchIndex(String key, String value) {
        addHotSearchIndex(key, value, 1);
    }

    /**
     * 添加热搜数据的热搜指数
     * @param key
     * @param value
     */
    @Override
    public void addHotSearchIndex(String key, String value, int times) {
        redisUtil.zIncrementScore(key, value, times);
    }

    /**
     * 获取元素的分数
     * @param key
     * @param value
     * @return
     */
    @Override
    public Double getHotSearchScore(String key, String value) {
        return redisUtil.zScore(key, value);
    }
}
